<?php
/**
 * Persevere_Client
 *
 * @package    Persevere
 * @subpackage Proxyobject
 * @version    $Id: Proxyobject.php 18 2009-05-05 13:42:46Z flassen $
 * @copyright  Copyright (c) 2009 flassen[ at ] g m a i l
 * @license    http://www.opensource.org/licenses/bsd-license.php
 */
class Persevere_Proxyobject {
  /**
   * Persevere doesn't always return "full ids" ({Class}/{id}), so this for help
   * @var unknown_type
   */
  private $_classHint = NULL;
  /**
  *
  * @var unknown_type
  */
  private $_decoratorObject = NULL;

  /**
   * Reference to the persevereclient object
   * @var PersevereClient
   */
  private $_persevereClient = NULL;

  /**
   * Construct and hydrate a proxy object
   * @param $values  array   values
   * @param $_classHint  string
   * @return void
   */
  function __construct( $values=NULL, $_classHint=NULL ) {
    foreach ($values as $k=>$v) {
      $this->{$k} = $v;
    }
    // if we have an implicit class that isnt stored
    $this->_classHint = $_classHint;
  }

  /**
   * "Magic" overloading
   *
   * @param $method
   * @param $args
   * @return mixed
   * @throws Persevere_Exception
   */
  function __call( $method, $args ) {
    if ( isset($this->_decoratorObject) && method_exists($this->_decoratorObject, $method ) ) {
      // @todo add a reference to this object the methods - or should we
      // array_unshift( $args, $this );
      // return call_user_func_array( array($this->_decoratorObject, $method), $args);
    } elseif ( method_exists($this, $method) ) {
      return call_user_func_array( array($this, $method), $args);
    }
    // @todo - should we automagically JSON-RPC?
    throw new Persevere_Exception("Unknown method '$method' called on object $this", 404);
  }

  /**
   * Update
   * @param $options
   * @return unknown_type
   */
  function update( $options=array() ) {
    // determine id ...
    if ( $fid = $this->getFullId() ) {
      $this->getPersevereClient()->update( $fid, $this, $options );
    }
  }

  /**
   * Delete object
   * @return bool
   */
  function remove() {
    // determine id ...
    if ( $fid = $this->getFullId() ) {
      return $this->getPersevereClient()->remove( $fid );
    }
  }

  /**
   * Execute a JSON RPC Call on this object
   * @param $method
   * @param $args
   * @return mixed
   */
  function jsonRpc($method, $args) {
    // determine id ...
    if ( $fid = $this->getFullId() ) {
      return $this->getPersevereClient()->jsonRpc( $fid , $method, $args );
    }
  }

  /**
   * Magic helper to show an easily legible 
   * @return string
   */
  function __toString() {
    return Zend_Json::encode( $this ) ;
  }
  
  /**
   * Returns the numeric id of the object
   * @return int
   */
  function getId() {
    if (is_numeric($this->id)) {
      return (int) $this->id;
    } else {
	    list($class, $id)  = explode('/', $this->id);
	    return (int) $id;
    }
  }

  /**
   * Returns the full ({CLASS}/{id}) id of this object
   * @return    string      Full id {CLASS}/{id}
   * @throws   Exception    when we no full class/id combo can be establish   
   */
  function getFullId() {
    list($first, $second) = explode('/', $this->id);
    if ( $first && is_numeric($second) ) {
      return $this->id;
    } elseif ( $first && $second === NULL && $this->_classHint ) {
      return $this->_classHint.'/'.$first;
    } else {
      throw new Exception('Cannot determine class/id full id - use should set the implicit class!', 500);
    }
  }

  /**
   * Add decorator class to mix in functionality 
   * @todo  
   * @param $decorator
   * @return unknown_type
   */
  function _addDecorator( $decorator ) {}

  /**
   * Sets the reference to the client
   * @todo - refactor? this is not really efficient ..
   * @param $pc
   * @return void
   */
  function setPersevereClient( Persevere_Client $pc ) {
    $this->_persevereClient = $pc;
  }

  /**
   * Returns the refernece to the persevere client
   * @return Persevere_Client
   */
  function getPersevereClient() {
    return $this->_persevereClient;
  }
}